using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Xfinity.Maths;
using System;

namespace Xfinity.Engine
{
    /// <summary>
    /// A simple component that measures the frames per second.
    /// </summary>
    public class FpsCounter : DrawableGameComponent
    {
        private static string[] fpsText = new string[4096];
        private static string[] averageFpsText = new string[4096];
        static FpsCounter()
        {
            for (int i = 0; i < fpsText.Length; i++)
            {
                fpsText[i] = "FPS: " + i.ToString();
            }
            for (int i = 0; i < averageFpsText.Length; i++)
            {
                averageFpsText[i] = "Average FPS: " + i.ToString();
            }
            GC.Collect();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="FpsCounter"/> class.
        /// </summary>
        /// <param name="game">Game the game component should be attached to.</param>
        public FpsCounter(Game game)
            : base(game)
        {
            Visible = true;
            DrawOrder = int.MaxValue;
        }
        /// <summary>
        /// Called when the GameComponent needs to be updated.  Override this method with component-specific update code.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to Microsoft.Xna.Framework.GameComponent.Update(Microsoft.Xna.Framework.GameTime)</param>
        public override void Update(GameTime gameTime)
        {
            fps = (1000 / gameTime.ElapsedGameTime.TotalMilliseconds);
            if (fps > maxFps && !double.IsInfinity(fps))
            {
                maxFps = fps;
            }
            else if (fps < minFps != double.IsInfinity(fps) && !MathFunctions.Compare((float)fps, 0f))
            {
                minFps = fps;
            }
            frameNumber++;
            averageFps = (frameNumber / gameTime.TotalGameTime.TotalSeconds);

        }
        public void ResetFrameCount()
        {
            frameNumber = 0;
        }

        public override void Draw(GameTime gameTime)
        {
            batch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

            if (fps < 4096)
            {
                DrawHudText(fpsText[(int)fps], Vector2.One);
            }
            else
            {
                DrawHudText<int>("FPS: ", (int)fps, Vector2.One);
            }
            if (averageFps < 4096)
            {
                DrawHudText(averageFpsText[(int)averageFps], new Vector2(1, 12));
            }
            else
            {
                DrawHudText<int>("Average FPS: ", (int)averageFps, new Vector2(1, 12));
            }
            //string s = "FPS: " + fps.ToString() + "\nAverage FPS: " + averageFps.ToString() + "\nFrame number: " + frameNumber.ToString();
            //DrawHudText(s, Vector2.One, batch, font);
            
            DrawHudText<uint>("Frame number: ", frameNumber, new Vector2(1, 24));

            batch.End();

            GraphicsDevice.RenderState.DepthBufferEnable = true;
            base.Draw(gameTime);
        }

        private void DrawHudText<T>(string preText, T item, Vector2 position)
        {
            string itemString = preText + item.ToString();
            batch.DrawString(font, itemString, position + Vector2.One, Color.Black);
            batch.DrawString(font, itemString, position, Color.Wheat);
        }
        private void DrawHudText(string text, Vector2 position)
        {
            batch.DrawString(font, text, position + Vector2.One, Color.Black);
            batch.DrawString(font, text, position, Color.Wheat);
        }
        SpriteBatch batch;
        SpriteFont font;
        ContentManager content;
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                content = new ContentManager(Game.Services);
                batch = new SpriteBatch(GraphicsDevice);
                font = content.Load<SpriteFont>("Content/Fonts/Consolas-10");
            }
            base.LoadGraphicsContent(loadAllContent);
        }
        #region MinFps
        private static double minFps = double.PositiveInfinity;

        /// <summary>
        /// MinFps.
        /// </summary>
        public static double MinFps
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return minFps; }
        }
        #endregion
        #region MaxFps
        private static double maxFps = double.NegativeInfinity;

        /// <summary>
        /// MaxFps.
        /// </summary>
        public static double MaxFps
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return maxFps; }
        }
        #endregion
        #region AverageFps
        private static double averageFps;
        private static uint frameNumber;
        /// <summary>
        /// AverageFps.
        /// </summary>
        public static double AverageFps
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return averageFps; }
        }
        #endregion
        #region Fps
        private static double fps;

        /// <summary>
        /// Gets the FPS.
        /// </summary>
        /// <value>The FPS.</value>
        public static double Fps
        {
            [System.Diagnostics.DebuggerStepThroughAttribute]
            get { return fps; }
        }
        #endregion
        #region FrameNumber
        public uint FrameNumber
        {
            get { return frameNumber; }
        }
        #endregion
    }
}
